﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web;
using System.Xml;

namespace Wyn.PMS.Entity.Construction
{
    public static class DbContextBase
    {
        private static volatile IEnumerable<string> _baseDbTypeCache;
        
        private static volatile IEnumerable<BusinessDbConnection> _businessConnections;

        private static object lockThis = new object();

        public static IEnumerable<string> GetAllConnectionString()
        {
            BizDayRepository bizDayRepository = new BizDayRepository();

            if (_businessConnections == null)
            {
                lock (lockThis)
                {
                    if (_businessConnections == null)
                    {
                        _businessConnections = bizDayRepository.FindAll(string.Empty)
                            .Where(b => !string.IsNullOrEmpty(b.ConnectionString))
                            .Select(b => new BusinessDbConnection { HotelID = b.HotelID, ConnectionString = b.ConnectionString })
                            .ToList();

                        Thread.MemoryBarrier();
                    }
                }
            }

            return _businessConnections.Select(b => b.ConnectionString).Distinct();
        }

        public static string GetConnectionString(string hotelId,bool isBase)
        {
            if (!isBase) return GetConnectionString(hotelId);
            
            string baseConnectionString = "name=PmsBaseEntities";

            return baseConnectionString;
        }
        
        public static string GetConnectionString(string hotelId)
        {
            BizDayRepository bizDayRepository = new BizDayRepository();
            if(_businessConnections == null)
            {
                lock (lockThis)
                {
                    if (_businessConnections == null)
                    {
                        _businessConnections = bizDayRepository.FindAll(string.Empty)
                            .Where(b => !string.IsNullOrEmpty(b.ConnectionString))
                            .Select(b => new BusinessDbConnection { HotelID = b.HotelID, ConnectionString = b.ConnectionString })
                            .ToList();

                        Thread.MemoryBarrier();
                    }
                }
            }
            if(_businessConnections==null)
            {
                throw new ArgumentNullException("Database Create faild，please contact CnAlexi@gmail.com");
            }
            BusinessDbConnection connection = _businessConnections.SingleOrDefault(s => s.HotelID == hotelId);
            if (connection == null)
            {
                _businessConnections = bizDayRepository.FindAll(string.Empty)
                            .Where(b => !string.IsNullOrEmpty(b.ConnectionString))
                            .Select(b => new BusinessDbConnection { HotelID = b.HotelID, ConnectionString = b.ConnectionString })
                            .ToList();
                connection = _businessConnections.SingleOrDefault(s => s.HotelID == hotelId);
            }
            if (connection == null)
            {
                throw new ArgumentNullException("Database connected faild，please check Hotel ID:" + hotelId + "is initialize");
            }
            return connection.ConnectionString;
        }
        
        private static IEnumerable<string> GetBaseDbTypeCache()
        {
            if (_baseDbTypeCache == null)
            {
                lock (lockThis)
                {
                    if (_baseDbTypeCache == null)
                    {
                        _baseDbTypeCache = GetBaseDbTypes();
                        Thread.MemoryBarrier();
                    }
                }
            }
            return _baseDbTypeCache;
        }
        
        public static bool Contains(string typeName)
        {
            return GetBaseDbTypeCache().Contains(typeName);
        }

        private static IEnumerable<string> GetBaseDbTypes()
        {
            XmlDocument doc = new XmlDocument();
            string root = System.Web.Hosting.HostingEnvironment.MapPath("~") != null
                ? System.Web.Hosting.HostingEnvironment.MapPath("~") + @"\bin\"
                : string.Empty;
            if(string.IsNullOrEmpty(root)){
                root = ( HttpContext.Current != null )
                              ? HttpContext.Current.Request.MapPath("~") + @"\bin\"
                              : string.Empty;
            }
            string path = root+@"BaseDBType.xml";
            doc.Load(path);
            XmlNodeList baseDbTypeNodes = doc.SelectNodes("/BaseDBType/type");
            IList<string> baseDbTypes = new List<string>();
            foreach (XmlNode node in baseDbTypeNodes)
            {
                string type = node.Attributes["name"].Value;

                baseDbTypes.Add(type);
            }

            return baseDbTypes;
        }

    }
}
